package maquinaVirtual;

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.List;
import java.util.Stack;

import maquinaPila.Instruction;

public class MaquinaVirtual implements Serializable {
	private static final long serialVersionUID = 1L;

	private static final int TAM_MEMORIA = 2048;

	private Stack<Integer> pilaEvaluacion;

	private Instruction[] programa;
	private int cp;
	
	private Integer[] memoria;

	@SuppressWarnings("unchecked")
	public MaquinaVirtual(String fprograma) {
		try {
			pilaEvaluacion = new Stack<Integer>();
			
			List<Instruction> instrucciones = (List<Instruction>) new ObjectInputStream(
					new FileInputStream(fprograma)).readObject();
			programa = new Instruction[instrucciones.size()];

			memoria = new Integer[TAM_MEMORIA];
			
			int j = 0;
			for (Instruction i : instrucciones)
				programa[j++] = i;
			cp = 0;

		} catch (Exception e) {
			System.err.println("Error al cargar el programa:" + e);
			System.exit(1);
		}
	}

	public void run(boolean traza) {
		if (traza) {
			System.out.println(pilaEvaluacion + "\n");
		}
		while (cp < programa.length) {
			if (traza) {
				System.out.print(programa[cp] + "=>");
			}
			programa[cp].ejecuta(this);
			if (traza) {
				System.out.println(pilaEvaluacion);
				imprimirMemoria();
				System.out.println();
			}
		}
	}

	public void push(Integer value) {
		pilaEvaluacion.push(value);
	}

	public Integer pop() {
		return pilaEvaluacion.pop();
	}
	
	public Integer lastElement() {
		return pilaEvaluacion.lastElement();
	}
	
	public void flip() {
		Integer cima = pilaEvaluacion.pop();
		Integer subcima = pilaEvaluacion.pop();
		pilaEvaluacion.push(cima);
		pilaEvaluacion.push(subcima);
	}
	
	public int getCP() {
		return cp;
	}
	
	public void incCP() {
		cp++;
	}

	public void setCP(int cp) {
		this.cp = cp;
	}

	public void setValMemoria(Integer val, int index) {
		memoria[index] = val;
	}

	public Integer getValMemoria(int index) {
		return memoria[index];
	}

	private void imprimirMemoria() {
		System.out.println("--------------------------------");
		for (int i = 0; i <= cp; i++) {
			if (memoria[i] != null) {
				System.out.print("[" + (i) + "] = ");
				System.out.print(memoria[i]);
				System.out.print(" | ");
			}
		}
		System.out.println();
		System.out.println("--------------------------------");

	}

	public static void main(String[] args) {
		if (args.length != 1) {
			System.err.println("ERROR - debe indicarse archivo a interpretar");
			System.exit(1);
		}
		MaquinaVirtual mv = new MaquinaVirtual(args[0]);
		mv.run(false);
	}

}
